﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Fst.SemiRing
{
    /// <summary>
    /// Tropical semiring implementation.
    /// 
    /// @author "John Salatas <jsalatas@users.sourceforge.net>"
    /// </summary>
    public class TropicalSemiring: Semiring
    {
        private static long serialVersionUID = 2711172386738607866L;

        // zero value
        public static float _zero = float.PositiveInfinity;

        // one value
        public static float _one = 0.0f;

        /*
        /// (non-Javadoc)
        /// 
        /// @see
        /// edu.cmu.sphinx.fst.weight.AbstractSemiring#Plus(edu.cmu.sphinx.fst.weight
        /// .float, edu.cmu.sphinx.fst.weight.float)
         */
        override public float plus(float w1, float w2) 
        {
            if (!isMember(w1) || !isMember(w2)) {
                return float.NegativeInfinity;
            }

            return w1 < w2 ? w1 : w2;
        }

        /*
        /// (non-Javadoc)
        /// 
        /// @see
        /// edu.cmu.sphinx.fst.weight.AbstractSemiring#Times(edu.cmu.sphinx.fst.weight
        /// .float, edu.cmu.sphinx.fst.weight.float)
         */
        override public float times(float w1, float w2) 
        {
            if (!isMember(w1) || !isMember(w2)) {
                return float.NegativeInfinity;
            }

            return w1 + w2;
        }

        /*
        /// (non-Javadoc)
        /// 
        /// @see
        /// edu.cmu.sphinx.fst.weight.AbstractSemiring#Divide(edu.cmu.sphinx.fst.
        /// weight.float, edu.cmu.sphinx.fst.weight.float)
         */
        override public float divide(float w1, float w2) 
        {
            if (!isMember(w1) || !isMember(w2)) {
                return float.NegativeInfinity;
            }

            if (w2 == TropicalSemiring._zero) 
            {
                return float.NegativeInfinity;
            } else if (w1 == TropicalSemiring._zero) {
                return TropicalSemiring._zero;
            }

            return w1 - w2;
        }

        /*
        /// (non-Javadoc)
        /// 
        /// @see edu.cmu.sphinx.fst.weight.AbstractSemiring#zero()
         */

        override public float zero() {
            return _zero;
        }

        /*
        /// (non-Javadoc)
        /// 
        /// @see edu.cmu.sphinx.fst.weight.AbstractSemiring#one()
         */

        override public float one() {
            return _one;
        }

        /*
        /// (non-Javadoc)
        /// 
        /// @see
        /// edu.cmu.sphinx.fst.weight.AbstractSemiring#isMember(edu.cmu.sphinx.fst
        /// .weight.float)
         */
        override public Boolean isMember(float w) {
            return (!float.IsNaN(w)) // not a NaN
                    && (w != float.NegativeInfinity); // and different from -inf
        }

        /*
        /// (non-Javadoc)
        /// 
        /// @see edu.cmu.sphinx.fst.semiring.Semiring#reverse(float)
         */
        override public float reverse(float w1) {
            return w1;
        }
    }
}
